/*********************************************************
 *
 * Filename: common/misc/cm_fifo.c
 *   Author: jmdvirus
 *   Create: 2019年03月28日 星期四 15时07分46秒
 *
 *********************************************************/

#include <stdio.h>

#include <fcntl.h>
#include <malloc.h>
#include <pthread.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include "cm_fifo.h"

#include "utils/rt_print.h"

typedef struct
{
    char               szPath[256];
    int                iFifo;
    int                iFD;
    char               szData[1024];
    int                iLen;
    fifo_read_callback cb;

    pthread_t iThread;
    int       iExit;
} CMFifoHandleInfo;

void *cm_fifo_r_thread(void *args)
{
    rtdebug("fifo read thread start\n");
    CMFifoHandleInfo *in = (CMFifoHandleInfo *)args;

    while (!in->iExit)
    {
        if (in->iFD <= 0)
        {
            in->iFD = open(in->szPath, O_RDONLY | O_NONBLOCK);
            if (in->iFD < 0)
            {
                sleep(1);
                continue;
            }
            else
            {
                rtdebug("fifo read open success\n");
            }
        }
        in->iLen = 1024;
        memset(in->szData, 0, sizeof(in->szData));
        in->iLen = read(in->iFD, in->szData, in->iLen);

        if (in->iLen > 0)
        {
            if (in->szData[in->iLen - 1] == '\n')
            {
                in->szData[in->iLen - 1] = '\0';
            }
            rtdebug("fifo read thread read out data len [%d] [%s]\n", in->iLen,
                    in->szData);
            if (in->cb)
            {
                in->cb(in->szData, in->iLen);
            }
        }

        sleep(1);
    }

    rtdebug("fifo read thread exit\n");
    return NULL;
}

int cm_fifo_r_open(CMFifoReadHandle *fd, const char *path,
                   fifo_read_callback callback)
{
    if (!path)
        return -1;

    CMFifoHandleInfo *in = (CMFifoHandleInfo *)malloc(sizeof(CMFifoHandleInfo));
    if (!in)
        return -2;

    strncpy(in->szPath, path, sizeof(in->szPath));

    in->cb = callback;

    in->iFD = open(in->szPath, O_RDONLY | O_NONBLOCK);
    if (in->iFD < 0)
    {
        rterror("fifo read open fail\n");
    }

    int ret = pthread_create(&in->iThread, NULL, cm_fifo_r_thread, in);
    if (ret < 0)
    {
        rterror("pthread_create fail\n");
        free(in);
        return -5;
    }

    in->iExit = 0;
    pthread_detach(in->iThread);

    rtdebug("fifo read open success\n");

    if (fd)
        *fd = in;

    return 0;
}

int cm_fifo_r_close(CMFifoReadHandle *fd)
{
    if (!fd || !*fd)
        return -1;
    rtdebug("fifo read close \n");
    CMFifoHandleInfo *in = *fd;
    in->iExit            = 1;
    // TODO: Use sema
    sleep(1);
    free(in);
    return 0;
}

int cm_fifo_w_open(CMFifoWriteHandle *fd, const char *path)
{
    if (!path)
        return -1;

    CMFifoHandleInfo *in = (CMFifoHandleInfo *)malloc(sizeof(CMFifoHandleInfo));
    if (!in)
        return -3;
    strncpy(in->szPath, path, sizeof(in->szPath));

    if (access(in->szPath, F_OK) == 0)
    {
        mkfifo(in->szPath, 0644);
    }
    int fdd = open(path, O_WRONLY);
    if (fdd < 0)
        return -2;

    in->iFD = fdd;

    if (fd)
        *fd = in;

    rtdebug("fifo write open success\n");

    return 0;
}

int cm_fifo_w_write(CMFifoWriteHandle fd, const char *data, int len)
{
    if (!fd || !data || len <= 0)
        return -201;
    CMFifoHandleInfo *in  = (CMFifoHandleInfo *)fd;
    int               ret = write(in->iFD, data, len);
    return ret;
}

int cm_fifo_w_close(CMFifoWriteHandle *fd)
{
    if (!fd || !*fd)
        return -1;
    CMFifoHandleInfo *in = (CMFifoHandleInfo *)*fd;
    free(in);
    return 0;
}

#ifdef __MAINTEST

void *ff_cb(char *data, int len)
{
    printf("ff_cb result: %d, [%s]\n", len, data);
    return NULL;
}

int main(int argc, char **args)
{

    CM_LOG_PRINT_INIT("fiforead");

    CMFifoReadHandle fd;
    cm_fifo_r_open(&fd, "/tmp/test_cmd", ff_cb);

    while (1)
    {
        sleep(1);
    }
    return 0;
}
#endif
